#include "FontPreviewProc.h"
#include "resource.h"
#include "Common.h"
#include <stdio.h>

unsigned char asciiWidths[sizeof(ascii) - 1];

static void WriteGBAFontToFile(FILE* file, HWND dlgWnd)
{
	int fontSel = SendDlgItemMessage(dlgWnd, IDC_FONTLIST, LB_GETCURSEL, 0, 0);
	int sizeSel = SendDlgItemMessage(dlgWnd, IDC_FONTSIZELIST, LB_GETCURSEL, 0, 0);
	int boldSel = SendDlgItemMessage(dlgWnd, IDC_CHKBOLD, BM_GETCHECK, 0, 0);
	int italicSel = SendDlgItemMessage(dlgWnd, IDC_CHKITALIC, BM_GETCHECK, 0, 0);

	if (fontSel != LB_ERR && sizeSel != LB_ERR)
	{
		static const unsigned short gbaWhite = 0x7FFF;
		static const unsigned short gbaBlack = 0;
		static const unsigned short gbaGreen = 0x03E0;
		static const unsigned short gbaRed   = 0x001F;

		unsigned int i, j;
		HGDIOBJ oldFont;
		const char* ccp;
		unsigned char* ucp;
		char fontName[128];
		unsigned short bitmapW, bitmapH;
		unsigned char fontSize;
		RECT r;
		HFONT font;
		LOGBRUSH lbrush;
		HBRUSH brush;
		HBITMAP bitmap;
		HDC bitmapDC;
		HDC dc = GetDC(NULL);

		// Get font size
		fontSize = (unsigned char)atoi(fontSizes[sizeSel]);

		fontSize <<= 1;

		// Write letter height
		fwrite(&fontSize, sizeof(unsigned char), 1, file);

		fontSize >>= 1;

		for (ucp = asciiWidths; *ucp != '\0'; ++ucp)
		{
			// Write letter width
			fwrite(ucp, sizeof(unsigned char), 1, file);
		}

		// Write letter offsets & widths table while we're at adding up bitmapW
		bitmapW = 0;
		for (ucp = asciiWidths; *ucp != '\0'; ++ucp)
		{
			// Col offset
			fwrite(&bitmapW, sizeof(unsigned short), 1, file);
			
			bitmapW += *ucp;
		}

		// Calculate actual bitmap height (twice of "point" size)
		bitmapH = fontSize*2;

		// Write bitmap dimensions
		fwrite(&bitmapW, sizeof(unsigned short), 1, file);
		fwrite(&bitmapH, sizeof(unsigned short), 1, file);


		// Create bitmap
		bitmap = CreateCompatibleBitmap(dc, bitmapW, bitmapH);

		// Create offscreen dc
		bitmapDC = CreateCompatibleDC(dc);

		// Select it with the bitmap
		SelectObject(bitmapDC, bitmap);
		
		/// Now lets fill bitmapdc with drawn font

		// Get font size
		fontSize = atoi(fontSizes[sizeSel]);

		// Get font name
		SendDlgItemMessageA(dlgWnd, IDC_FONTLIST, LB_GETTEXT, fontSel, (LPARAM)(LPCTSTR)fontName);

		// Create font
		font = CreateFontA
			(
				-MulDiv(fontSize, GetDeviceCaps(dc, LOGPIXELSX), 72),
				0, 0, 0,
				boldSel ? FW_BOLD : 0,
				italicSel,
				0, 0, ANSI_CHARSET, 0, 0, NONANTIALIASED_QUALITY, 0,
				fontName
			);

		// Make brush to clear white
		lbrush.lbColor = RGB(255, 255, 255);
		lbrush.lbHatch = 0;
		lbrush.lbStyle = BS_SOLID;
		
		brush = CreateBrushIndirect(&lbrush);
		
		r.left   = 0;
		r.top    = 0;
		r.right  = bitmapW;
		r.bottom = bitmapH;

		// Clear to white
		FillRect(bitmapDC, &r, brush);

		// Delete brush
		DeleteObject(brush);

		oldFont = SelectObject(bitmapDC, font);

		// Draw characters
		for (ccp = ascii, ucp = asciiWidths, i = 0; *ccp != '\0'; ++ccp, i += *ucp, ++ucp)
			TextOutA(bitmapDC, i, 0, ccp, 1);

		// Write letter bitmaps
		for (j = 0; j < bitmapH; ++j)
		{
			for (i = 0; i < bitmapW; ++i)
			{
				if (GetRValue(GetPixel(bitmapDC, i, j)) == 255)
					fwrite(&gbaBlack, 2, 1, file);
				else
					fwrite(&gbaWhite, 2, 1, file);
			}
		}


		/// Cleanup

		// Select bitmapDC with oldFont
		SelectObject(bitmapDC, oldFont);

		// Delete font
		DeleteObject(font);
		
		// Release DC to preview wnd
		ReleaseDC(NULL, dc);
	}
}

static void UpdateFontPreview(HWND previewWnd, HWND dlgWnd, HBITMAP* bitmap, HDC* bitmapDC)
{
	int fontSel = SendDlgItemMessage(dlgWnd, IDC_FONTLIST, LB_GETCURSEL, 0, 0);
	int sizeSel = SendDlgItemMessage(dlgWnd, IDC_FONTSIZELIST, LB_GETCURSEL, 0, 0);
	int boldSel = SendDlgItemMessage(dlgWnd, IDC_CHKBOLD, BM_GETCHECK, 0, 0);
	int italicSel = SendDlgItemMessage(dlgWnd, IDC_CHKITALIC, BM_GETCHECK, 0, 0);

	if (fontSel != LB_ERR && sizeSel != LB_ERR)
	{
		unsigned int i, j, bitmapW, bitmapH;
		SIZE textDim;
		RECT r; // Size of preview wnd
		HGDIOBJ oldFont;
		const char* ccp;
		unsigned char* ucp;
		char fontName[128];
		int fontSize;
		HFONT font;
		LOGBRUSH lbrush;
		HBRUSH brush;
		
		// Get DC to preview wnd
		HDC dc = GetDC(previewWnd);

		// Get Size of preview wnd
		GetWindowRect(previewWnd, &r);

		bitmapW = r.right - r.left;
		bitmapH = r.bottom - r.top;

		// Create bitmap
		if (*bitmap)
			DeleteObject(*bitmap);
		*bitmap = CreateCompatibleBitmap(dc, bitmapW, bitmapH);

		// Create offscreen dc
		if (*bitmapDC)
			DeleteDC(*bitmapDC);
		*bitmapDC = CreateCompatibleDC(dc);

		// Select it with the bitmap
		SelectObject(*bitmapDC, *bitmap);
		
		/// Now lets fill bitmapdc with drawn font

		// Get font size
		fontSize = atoi(fontSizes[sizeSel]);

		// Get font name
		SendDlgItemMessageA(dlgWnd, IDC_FONTLIST, LB_GETTEXT, fontSel, (LPARAM)(LPCTSTR)fontName);

		// Create font
		font = CreateFontA
			(
				-MulDiv(fontSize, GetDeviceCaps(dc, LOGPIXELSX), 72),
				0, 0, 0,
				boldSel ? FW_BOLD : 0,
				italicSel,
				0, 0, ANSI_CHARSET, 0, 0, NONANTIALIASED_QUALITY, 0,
				fontName
			);


		// Make brush to clear white
		lbrush.lbColor = RGB(255, 255, 255);
		lbrush.lbHatch = 0;
		lbrush.lbStyle = BS_SOLID;
		
		brush = CreateBrushIndirect(&lbrush);
		
		r.left   = 0;
		r.top    = 0;
		r.right  = bitmapW;
		r.bottom = bitmapH;

		// Clear to white
		FillRect(*bitmapDC, &r, brush);

		// Delete brush
		DeleteObject(brush);

		oldFont = SelectObject(*bitmapDC, font);

		// Set asciiWidths
		for (ccp = ascii, ucp = asciiWidths; *ccp != '\0'; ++ccp, ++ucp)
		{
			GetTextExtentPoint32A(*bitmapDC, ccp, 1, &textDim);
			*ucp = (unsigned char)textDim.cx;
		}

		// Draw characters
		for (ccp = ascii, ucp = asciiWidths, i = 0, j = 0; *ccp != '\0'; ++ccp, ++ucp, ++i)
		{
			TextOutA(*bitmapDC, i, j, ccp, 1);
			i += *ucp;

			if (i > bitmapW)
			{
				i = 0;
				j += fontSize*2;
			}
		}

#if 0
		for (i = 0; i < bitmapW; ++i)
		{
			for (j = 0; j < bitmapH; ++j)
			{
				COLORREF c = GetPixel(*bitmapDC, i, j);
				if (GetRValue(c) != 0 || GetGValue(c) != 0 || GetBValue(c) != 0)
					SetPixel(*bitmapDC, i, j, RGB(255, 255, 255));
			}
		}
#endif

		SelectObject(*bitmapDC, oldFont);

		// Delete font
		DeleteObject(font);
		
		// Release DC to preview wnd
		ReleaseDC(previewWnd, dc);
	}
}

LRESULT CALLBACK FontPreviewProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	static HBITMAP bitmap;
	static HDC     bitmapDC;
	static HWND    dlgWnd;
	HDC            hdc;
	PAINTSTRUCT    ps;
	RECT           rect;

	switch (msg)
	{
	case WM_CREATE:
		{
			dlgWnd = GetParent(wnd);
			bitmap = NULL;
			bitmapDC = NULL;
			return 0;
		}
	case WM_USER:
		{
			UpdateFontPreview(wnd, dlgWnd, &bitmap, &bitmapDC);
			InvalidateRect(wnd, NULL, FALSE);
			return 0;
		}
	case WM_USER + 1:
		{
			WriteGBAFontToFile((FILE*)wParam, dlgWnd);
			return 0;
		}
	case WM_PAINT:
		{
			hdc = BeginPaint(wnd, &ps);

			GetClientRect(wnd, &rect);

			if (!bitmap || !bitmapDC)
				UpdateFontPreview(wnd, dlgWnd, &bitmap, &bitmapDC);

			BitBlt(hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left,
				ps.rcPaint.bottom - ps.rcPaint.top, bitmapDC, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);

			EndPaint(wnd, &ps);
			return 0;
		}
	case WM_DESTROY:
		{
			if (bitmap)
				DeleteObject(bitmap);
			if (bitmapDC)
				DeleteDC(bitmapDC);
			PostQuitMessage (0);
			return 0;
		}
	}
	return DefWindowProc(wnd, msg, wParam, lParam);

}